import { MULTIPLE_TABS_KEY } from "@/enums/cacheEnum";
import projectSetting from "@/settings/projectSetting";
import { Persistent } from "@/utils/cache/persistent";
import { RouteLocationNormalized, RouteLocationRaw, Router } from "vue-router";
import type { State, RootState } from "@vue/runtime-core";
import { ActionContext } from "vuex";
import { getRawRoute } from "@/router";
import { toRaw, unref } from "vue";
import { useGo, useRedo } from "@/hooks/web/usePage";
import { PageEnum } from "@/enums/pageEnum";
import { Index } from "/#/config";

export interface MultipleTabState {
  cacheTabList: Set<string>;
  tabList: RouteLocationNormalized[];
  lastDragEndIndex: number;
}
const cacheTab = projectSetting.multiTabsSetting.cache;

const getToTarget = (tabItem: RouteLocationNormalized) => {
  const { params, path, query } = tabItem;
  return {
    params: params || {},
    path,
    query: query || {},
  };
};

const multipleTabStore = {
  namespace: true,
  state: (): MultipleTabState => ({
    // Tabs that need to be cached
    cacheTabList: new Set(),
    // multiple tab list
    tabList: cacheTab ? Persistent.getLocal(MULTIPLE_TABS_KEY) || [] : [],
    lastDragEndIndex: 0,
  }),
  getters: {
    getTabList(state: State): RouteLocationNormalized[] {
      return state.tabList;
    },
    getCachedTabList(state: State): string[] {
      return Array.from(state.cacheTabList);
    },
    getLastDragEndIndex(state: State): number {
      return state.lastDragEndIndex;
    },
  },
  mutations: {
    SET_TAB_LIST: (state: State) => {},
    ADD_TAB_LIST: (state: State, route: RouteLocationNormalized) => {
      state.tabList.push(route);
    },
    SET_CACHED_TAB_LIST: (state: State, cacheMap: Set<string>) => {
      state.cacheTabList = cacheMap;
    },
    DELETE_CACHED_TAB_LIST: (state: State, tab: string) => {
      state.cacheTabList.delete(tab);
    },
    SET_LAST_DRAG_END_INDEX: (state: State, add?: number) => {
      if (add) {
        state.lastDragEndIndex = state.lastDragEndIndex + add;
      }
    },
    UPDATE_TAB_NEW_INDEX: (
      state: State,
      { oldIndex, offset, currentValue, newIndex }: Index
    ) => {
      state.tabList.splice(oldIndex, offset);
      if (currentValue) {
        state.tabList.splice(oldIndex, 0, currentValue);
      }
    },
  },
  actions: {
    /**
     * 更新缓存当前打开的tabs
     * Update the cache according to the currently opened tabs
     */
    async updateCacheTab({ state, commit }: ActionContext<State, RootState>) {
      const cacheMap: Set<string> = new Set();

      for (const tab in state.tabList) {
        const item = getRawRoute(tab);
        const needCache = !item.meta?.noCache;
        if (!needCache) {
          continue;
        }
        const name = item.name as string;
        cacheMap.add(name);
      }
      commit("SET_CACHED_TAB_LIST", cacheMap);
    },
    /**
     * Refresh tabs
     */
    async refreshPage(
      { state, commit }: ActionContext<State, RootState>,
      router: Router
    ) {
      const { currentRoute } = router;
      const route = unref(currentRoute);
      const name = route.name;

      const findTab = state.getCachedTabList.find(
        (item: string) => item === name
      );
      if (findTab) {
        commit("DELETE_CACHED_TAB_LIST", findTab);
      }
      const redo = useRedo(router);
      await redo();
    },
    clearCacheTabs({ commit }: ActionContext<State, RootState>): void {
      commit("SET_CACHED_TAB_LIST", new Set());
    },
    resetState({ commit, dispatch }: ActionContext<State, RootState>): void {
      commit("SET_TAB_LIST", []);
      dispatch("clearCacheTabs");
    },
    // goToPage(router: Router) {
    //   const go = useGo(router);
    //   const len = this.tabList.length;
    //   const { path } = unref(router.currentRoute);

    //   let toPath: PageEnum | string = PageEnum.BASE_HOME;

    //   if (len > 0) {
    //     const page = this.tabList[len - 1];
    //     const p = page.fullPath || page.path;
    //     if (p) {
    //       toPath = p;
    //     }
    //   }
    //   // Jump to the current page and report an error
    //   path !== toPath && go(toPath as PageEnum, true);
    // },

    async addTab(
      { commit, state, dispatch }: ActionContext<State, RootState>,
      route: RouteLocationNormalized
    ) {
      const { path, name, fullPath, params, query, meta } = getRawRoute(route);
      // 404  The page does not need to add a tab
      if (
        path === PageEnum.ERROR_PAGE ||
        path === PageEnum.BASE_LOGIN ||
        !name ||
        ["RedirectTo", "NotFound"].includes(name as string)
      ) {
        return;
      }
      let updateIndex = -1;
      // Existing pages, do not add tabs repeatedly
      const tabHasExits = state.tabList.some(
        (tab: RouteLocationNormalized, index: number) => {
          updateIndex = index;
          return (tab.fullPath || tab.path) === (fullPath || path);
        }
      );
      // If the tab already exists, perform the update operation
      if (tabHasExits) {
        const curTab = toRaw(state.tabList)[updateIndex];
        if (!curTab) {
          return;
        }
        curTab.params = params || curTab.params;
        curTab.query = query || curTab.query;
        curTab.fullPath = fullPath || curTab.fullPath;
        commit("UPDATE_TAB_NEW_INDEX", {
          oldIndex: updateIndex,
          offset: 1,
          currentValue: curTab,
        });
      } else {
        // Add tab
        // 获取动态路由打开数，超过 0 即代表需要控制打开数
        const dynamicLevel: any = meta?.dynamicLevel ?? -1;
        if (dynamicLevel > 0) {
          // 如果动态路由层级大于 0 了，那么就要限制该路由的打开数限制了
          // 首先获取到真实的路由，使用配置方式减少计算开销.
          // const realName: string = path.match(/(\S*)\//)![1];

          // 获取到已经打开的动态路由数, 判断是否大于某一个值
          if (
            state.tabList.filter(
              (e: RouteLocationNormalized) => e.path ?? "" === path
            ).length >= dynamicLevel
          ) {
            // 关闭第一个
            const index = state.tabList.findIndex(
              (item: RouteLocationNormalized) => item.path === path
            );
            index !== -1 &&
              commit("UPDATE_TAB_NEW_INDEX", { oldeIndex: index, offset: 1 });
          }
        }
        commit("ADD_TAB_LIST", route);
      }
      dispatch("updateCacheTab");
      cacheTab && Persistent.setLocal(MULTIPLE_TABS_KEY, state.tabList);
    },

    async closeTab(
      { commit, state }: ActionContext<State, RootState>,
      { tab, router }: any
    ) {
      const close = (route: RouteLocationNormalized) => {
        const { fullPath, meta: { affix } = {} } = route;
        if (affix) {
          return;
        }
        const index = state.tabList.findIndex(
          (item: RouteLocationNormalized) => item.fullPath === fullPath
        );
        index !== -1 &&
          commit("UPDATE_TAB_NEW_INDEX", { oldIndex: index, offset: 1 });
      };

      const { currentRoute, replace } = router;

      const { path } = unref(currentRoute);
      if (path !== tab.path) {
        // Closed is not the activation tab
        close(tab);
        return;
      }

      // Closed is activated atb
      let toTarget: RouteLocationRaw = {};

      const index = state.tabList.findIndex(
        (item: RouteLocationNormalized) => item.path === path
      );

      // If the current is the leftmost tab
      if (index === 0) {
        // There is only one tab, then jump to the homepage, otherwise jump to the right tab
        if (state.tabList.length === 1) {
          // const userStore = useUserStore();
          // toTarget = userStore.getUserInfo.homePath || PageEnum.BASE_HOME;
        } else {
          //  Jump to the right tab
          const page = state.tabList[index + 1];
          toTarget = getToTarget(page);
        }
      } else {
        // Close the current tab
        const page = state.tabList[index - 1];
        toTarget = getToTarget(page);
      }
      close(currentRoute.value);
      await replace(toTarget);
    },

    // // Close according to key
    async closeTabByKey(
      { state, dispatch }: ActionContext<State, RootState>,
      { key, router }: any
    ) {
      const index = state.tabList.findIndex(
        (item: RouteLocationNormalized) => (item.fullPath || item.path) === key
      );
      if (index !== -1) {
        await dispatch("closeTab", {
          tab: state.tabList[index],
          router: router,
        });
        const { currentRoute, replace } = router;
        // 检查当前路由是否存在于tabList中
        const isActivated = state.tabList.findIndex(
          (item: RouteLocationNormalized) => {
            return item.fullPath === currentRoute.value.fullPath;
          }
        );
        // 如果当前路由不存在于TabList中，尝试切换到其它路由
        if (isActivated === -1) {
          let pageIndex;
          if (index > 0) {
            pageIndex = index - 1;
          } else if (index < state.tabList.length - 1) {
            pageIndex = index + 1;
          } else {
            pageIndex = -1;
          }
          if (pageIndex >= 0) {
            const page = state.tabList[index - 1];
            const toTarget = getToTarget(page);
            await replace(toTarget);
          }
        }
      }
    },

    // Sort the tabs
    async sortTabs(
      { commit, state }: ActionContext<State, RootState>,
      oldIndex: number,
      newIndex: number
    ) {
      console.log("排序");
      const currentTab = state.tabList[oldIndex];
      commit("UPDATE_TAB_NEW_INDEX");
      commit("UPDATE_TAB_NEW_INDEX", {
        oldIndex: oldIndex,
        newIndex: newIndex,
        currentTab: currentTab,
      });
      commit("SET_LAST_DRAG_END_INDEX", 1);
    },

    // // Close the tab on the right and jump
    // async closeLeftTabs(route: RouteLocationNormalized, router: Router) {
    //   const index = this.tabList.findIndex((item) => item.path === route.path);

    //   if (index > 0) {
    //     const leftTabs = this.tabList.slice(0, index);
    //     const pathList: string[] = [];
    //     for (const item of leftTabs) {
    //       const affix = item?.meta?.affix ?? false;
    //       if (!affix) {
    //         pathList.push(item.fullPath);
    //       }
    //     }
    //     this.bulkCloseTabs(pathList);
    //   }
    //   this.updateCacheTab();
    //   handleGotoPage(router);
    // },

    // // Close the tab on the left and jump
    // async closeRightTabs(route: RouteLocationNormalized, router: Router) {
    //   const index = this.tabList.findIndex((item) => item.fullPath === route.fullPath);

    //   if (index >= 0 && index < this.tabList.length - 1) {
    //     const rightTabs = this.tabList.slice(index + 1, this.tabList.length);

    //     const pathList: string[] = [];
    //     for (const item of rightTabs) {
    //       const affix = item?.meta?.affix ?? false;
    //       if (!affix) {
    //         pathList.push(item.fullPath);
    //       }
    //     }
    //     this.bulkCloseTabs(pathList);
    //   }
    //   this.updateCacheTab();
    //   handleGotoPage(router);
    // },

    // async closeAllTab(router: Router) {
    //   this.tabList = this.tabList.filter((item) => item?.meta?.affix ?? false);
    //   this.clearCacheTabs();
    //   this.goToPage(router);
    // },

    // /**
    //  * Close other tabs
    //  */
    // async closeOtherTabs(route: RouteLocationNormalized, router: Router) {
    //   const closePathList = this.tabList.map((item) => item.fullPath);

    //   const pathList: string[] = [];

    //   for (const path of closePathList) {
    //     if (path !== route.fullPath) {
    //       const closeItem = this.tabList.find((item) => item.path === path);
    //       if (!closeItem) {
    //         continue;
    //       }
    //       const affix = closeItem?.meta?.affix ?? false;
    //       if (!affix) {
    //         pathList.push(closeItem.fullPath);
    //       }
    //     }
    //   }
    //   this.bulkCloseTabs(pathList);
    //   this.updateCacheTab();
    //   handleGotoPage(router);
    // },

    // /**
    //  * Close tabs in bulk
    //  */
    // async bulkCloseTabs(pathList: string[]) {
    //   this.tabList = this.tabList.filter((item) => !pathList.includes(item.fullPath));
    // },

    // /**
    //  * Set tab's title
    //  */
    // async setTabTitle(title: string, route: RouteLocationNormalized) {
    //   const findTab = this.getTabList.find((item) => item === route);
    //   if (findTab) {
    //     findTab.meta.title = title;
    //     await this.updateCacheTab();
    //   }
    // },
    // /**
    //  * replace tab's path
    //  * **/
    // async updateTabPath(fullPath: string, route: RouteLocationNormalized) {
    //   const findTab = this.getTabList.find((item) => item === route);
    //   if (findTab) {
    //     findTab.fullPath = fullPath;
    //     findTab.path = fullPath;
    //     await this.updateCacheTab();
    //   }
    // },
  },
};

export default multipleTabStore;
